//
//  FFBindUnit.m
//  FFMVVM
//
//  Created by AKsoftware on 2016/11/1.
//  Copyright © 2016年 AKsoftware. All rights reserved.
//

#import "FFBindUnit.h"
#import "FFKVOBindSendCenter.h"
#import "NSObject+FFBind.h"

@interface FFBindUnit ()

@property (nonatomic, weak) dispatch_queue_t performQueue;
@property (nonatomic, weak) NSThread *performThread;

@property (nonatomic, copy) id performBlock;

@end

@implementation FFBindUnit

- (instancetype)initTarget:(NSObject *)target
                  observer:(NSObject *)observer
                 indentify:(NSString *)indentify
             performThread:(NSThread *)thread
              performBlock:(id)block
{
    return [self initTarget:target
                   observer:observer
                  indentify:indentify
               performQueue:nil
              performThread:thread
               performBlock:block];
}


- (instancetype)initTarget:(NSObject *)target
                  observer:(NSObject *)observer
                 indentify:(NSString *)indentify
              performQueue:(dispatch_queue_t)queue
              performBlock:(id)block
{
    return [self initTarget:target
                   observer:observer
                  indentify:indentify
               performQueue:queue
              performThread:nil
               performBlock:block];
}

- (instancetype)initTarget:(NSObject *)target
                  observer:(NSObject *)observer
                 indentify:(NSString *)indentify
              performQueue:(dispatch_queue_t)queue
             performThread:(NSThread *)thread
              performBlock:(id)block
{
    if (self = [super init]) {
        self.target = target;
        self.observer = observer;
        self.indentify = indentify;
        self.performQueue = queue;
        self.performThread = thread;
        self.performBlock = block;
        
        [target addBindUinit:self];
        [observer addBindUinit:self];
    }
    return self;
}

- (void)bind
{
    
    //do no
}
- (void)destoryBind
{
    self.target = nil;
    self.observer = nil;
    self.indentify = nil;
    self.performThread = nil;
    self.performBlock = nil;
}

- (void)dealloc
{
    [self destoryBind];
}

@end

@interface FFKVOBindUnit ()

@property (nonatomic, strong) NSArray *keyPathArray;
@property (nonatomic, copy) NSString *keyPath;

@end

@implementation FFKVOBindUnit

- (instancetype)initTarget:(NSObject *)target
                  observer:(NSObject *)observer
                   keyPath:(NSArray *)keyPathArray
                   options:(NSKeyValueObservingOptions)options
              performQueue:(dispatch_queue_t)queue
              performBlock:(void(^)(NSString *changeKey, id value))performBlock
{
    if (self = [super initTarget:target observer:observer indentify:nil performQueue:queue performBlock:performBlock]) {
        self.keyPathArray = keyPathArray;
        self.options = options;
        [self bind];
    }
    return self;
}

- (instancetype)initTarget:(NSObject *)target
                  observer:(NSObject *)observer
                   keyPath:(NSArray *)keyPathArray
                   options:(NSKeyValueObservingOptions)options
             performThread:(NSThread *)thread
              performBlock:(void(^)(NSString *changeKey, id value))performBlock
{
    if (self = [super initTarget:target
                        observer:observer
                       indentify:nil
                   performThread:thread
                    performBlock:performBlock])
    {
        self.keyPathArray = keyPathArray;
        self.options = options;
        [self bind];
    }
    return self;
}


- (void)bind
{
    [super bind];
    [[FFKVOBindSendCenter shareInstance] bindUnit:self];

    //bind
    for (NSString *key in self.keyPathArray) {
        [self perfomKvoBlock:key object:[self.target valueForKeyPath:key]];
    }
}

- (void)destoryBind
{
    [[FFKVOBindSendCenter shareInstance] destoryBindUnit:self];
    self.keyPathArray = nil;
    self.keyPath = nil;
    [super destoryBind];
}

- (void)perfomKvoBlock:(NSString *)key object:(id)value
{
    void (^block)(NSString *key, id value);
    NSThread *thread;
    dispatch_queue_t queue;
    @synchronized (self) {
        block = self.performBlock;
        thread = self.performThread;
        queue = self.performQueue;
    }
    
    if (thread) {
        if ([NSThread currentThread] == thread) {
            if (block) {
                block(key, value);
            }
        } else {
            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
            if (key) {
                [dic setObject:key forKey:@"key"];
            }
            if (value) {
                [dic setObject:value forKey:@"value"];
            }
            [self performSelector:@selector(threadPerformBlock:) onThread:thread withObject:dic waitUntilDone:NO];
        }
        return;
    }
    if (queue) {
        if ([[NSThread currentThread] isMainThread] && queue == dispatch_get_main_queue()) {
            if (block) {
                block(key, value);
            }
        } else {
            dispatch_async(queue, ^{
                if (block) {
                    block(key, value);
                }
            });
        }
        return;
    }
    
    if (block) {
        block(key, value);
    }
}

- (void)threadPerformBlock:(NSMutableDictionary *)dic
{
    void (^block)(NSString *key, id value);
    @synchronized (self) {
        block = self.performBlock;
    }
    if (block) {
        block(dic[@"key"], dic[@"value"]);
    }
}


@end
